/*
 *    Copyright (c) 2018-2025, cloud All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: cloud
 */
package com.fuyao.cloud.asset.purchaseApply.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyao.cloud.admin.api.entity.SysDept;
import com.fuyao.cloud.admin.api.feign.RemoteDeptService;
import com.fuyao.cloud.asset.budget.mapper.AssetBudgetMapper;
import com.fuyao.cloud.asset.budget.service.AssetBudgetService;
import com.fuyao.cloud.asset.constant.AssetConstant;
import com.fuyao.cloud.asset.constant.PurchaseConstant;
import com.fuyao.cloud.asset.dto.apply.PurchaseapplyCreateDTO;
import com.fuyao.cloud.asset.dto.apply.PurchaseapplyEditDTO;
import com.fuyao.cloud.asset.dto.apply.PurchaseapplySearchDTO;
import com.fuyao.cloud.asset.entity.*;
import com.fuyao.cloud.asset.entity.ac.AssetAcList;
import com.fuyao.cloud.asset.enums.AssetStatusEnum;
import com.fuyao.cloud.asset.purchaseApply.mapper.AssetPurchaseapplyMapper;
import com.fuyao.cloud.asset.purchaseApply.service.AssetPurchaseapplyService;
import com.fuyao.cloud.asset.purchaseApplyList.service.AssetPurchaseapplyListService;
import com.fuyao.cloud.asset.supplier.mapper.AssetSupplierMapper;
import com.fuyao.cloud.asset.supplier.service.AssetSupplierService;
import com.fuyao.cloud.asset.vo.FyAssetPurchaseapplyExcelVO;
import com.fuyao.cloud.asset.vo.apply.PurchaseapplyListPageVO;
import com.fuyao.cloud.asset.vo.apply.PurchaseapplyPageVO;
import com.fuyao.cloud.common.core.constant.CommonConstants;
import com.fuyao.cloud.common.core.model.BaseEntity;
import com.fuyao.cloud.common.core.util.DictItemOption;
import com.fuyao.cloud.common.core.util.R;
import com.fuyao.cloud.common.data.datascope.DataScope;
import com.fuyao.cloud.common.data.datascope.PageSelectScope;
import com.fuyao.cloud.common.data.resolver.DictItemResolver;
import com.fuyao.cloud.common.data.resolver.NumberResolver;
import com.fuyao.cloud.common.data.resolver.ParamResolver;
import com.fuyao.cloud.common.security.service.CloudUser;
import com.fuyao.cloud.common.security.util.SecurityUtils;
import com.fuyao.cloud.flowable.feign.RemoteFlowableService;
import com.fuyao.cloud.flowable.vo.ReturnCode;
import com.fuyao.cloud.flowable.vo.ReturnVo;
import com.fuyao.cloud.flowable.vo.StartProcessInstanceVo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 采购申请
 *
 * @author 时间的朋友
 * @date 2021-11-22 13:58:37
 */
@Service
@RequiredArgsConstructor
public class AssetPurchaseapplyServiceImpl extends ServiceImpl<AssetPurchaseapplyMapper, AssetPurchaseapply> implements AssetPurchaseapplyService {
    private final RemoteDeptService remoteDeptService;
    private final AssetBudgetMapper budgetMapper;
    private final AssetSupplierMapper supplierMapper;
    private final AssetSupplierService supplierService;
    private final RemoteDeptService deptService;
    private final AssetBudgetService budgetService;
    private final AssetPurchaseapplyListService purchaseapplyListService;
    private final RemoteFlowableService remoteFlowableService;

    @Transactional
    @Override
    public boolean save(AssetPurchaseapply entity) {
        beforeSave(entity);
        boolean hasSave = super.save(entity);
        if (hasSave) {
            this.purchaseapplyListService.saveOrUpdateApplyList(entity);
        }
        return hasSave;
    }

    @Transactional
    @Override
    public boolean updateById(AssetPurchaseapply entity) {
        beforeSave(entity);
        boolean hasUpdate = super.updateById(entity);
        if (hasUpdate) {
            this.purchaseapplyListService.saveOrUpdateApplyList(entity);
        }
        return hasUpdate;
    }

    @Override
    public List<FyAssetPurchaseapplyExcelVO> listExcel(QueryWrapper queryWrapper) {
        String[] dictOptionTypes = new String[]{AssetConstant.PURCHASEAPPLY_STATUS, AssetConstant.TYPE_DOCUMENT, AssetConstant.CURRENCY_TYPE, AssetConstant.PURCHASE_WAY};
        Map<String, List<DictItemOption>> resultMap = DictItemResolver.getDictOptionResultMap(dictOptionTypes);
        List<AssetPurchaseapply> excelVOList = this.list(queryWrapper);
        if (CollUtil.isNotEmpty(excelVOList)) {
            return excelVOList.stream().map(purchaseapply -> {
                FyAssetPurchaseapplyExcelVO excelVO = new FyAssetPurchaseapplyExcelVO();
                BeanUtil.copyProperties(purchaseapply, excelVO);
                excelVO.setStatus(DictItemResolver.getDictOptionLabel(resultMap.get(AssetConstant.PURCHASEAPPLY_STATUS), excelVO.getStatus()));
                excelVO.setType(DictItemResolver.getDictOptionLabel(resultMap.get(AssetConstant.TYPE_DOCUMENT), excelVO.getType()));
                excelVO.setCurrencyType(DictItemResolver.getDictOptionLabel(resultMap.get(AssetConstant.CURRENCY_TYPE), excelVO.getCurrencyType()));
                excelVO.setMethod(DictItemResolver.getDictOptionLabel(resultMap.get(AssetConstant.PURCHASE_WAY), excelVO.getMethod()));
                return excelVO;
            }).collect(Collectors.toList());
        }
        return Lists.newArrayList();
    }

    @Override
    public PurchaseapplyCreateDTO create() {
        CloudUser user = SecurityUtils.getUser();
        PurchaseapplyCreateDTO createDTO = new PurchaseapplyCreateDTO();
        createDTO.setCreateId(user.getId());
        createDTO.setCreateBy(user.getName());
        createDTO.setDeptId(user.getDeptId());
        createDTO.setDeptFullname(user.getFullName());
        createDTO.setCreateTime(LocalDateTimeUtil.now());
        createDTO.setUnid(UUID.randomUUID().toString());
        createDTO.setStatus(AssetConstant.DEFAULT_STATUS);
        createDTO.setCurrencyType(AssetConstant.DEFAULT_CURRENCY_TYPE);
        createDTO.setType(AssetConstant.DEFAULT_TYPE);
        createDTO.setDetailed(StrUtil.EMPTY);
        createDTO.setPurchaseOuid(user.getDeptId());
        createDTO.setPurchaseOuname(user.getOuName());
        createDTO.setPurchaseOufullname(user.getFullName());
        createDTO.setDictOption(getDictOption());

        // 生成单号
        String caseKey = ParamResolver.getStr(AssetConstant.PURCHASEAPPLY_CASE_VALUE, AssetConstant.PURCHASEAPPLY_CASE_DEFAULT_CODE_PREFIX);
        Map<String, String> numberMap = NumberResolver.getNumberMap(PurchaseConstant.PURCHASE_NUMBER_TYPE, DateUtil.format(new Date(), DatePattern.SIMPLE_MONTH_PATTERN), 5L).getData();
        createDTO.setCaseid(caseKey + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN) + numberMap.get("code"));

        return createDTO;
    }

    @Override
    public PurchaseapplyEditDTO edit(Long id) {
        AssetPurchaseapply purchaseapply = this.getById(id);
        Assert.isTrue(ObjectUtils.isNotEmpty(purchaseapply), String.format("%s不合法", id));
        PurchaseapplyEditDTO editDTO = new PurchaseapplyEditDTO();
        BeanUtil.copyProperties(purchaseapply, editDTO);
        List<AssetPurchaseapplyList> purchaseapplyList = this.purchaseapplyListService.list(Wrappers.<AssetPurchaseapplyList>query().lambda().eq(AssetPurchaseapplyList::getParentId, purchaseapply.getId()));
        if (CollUtil.isNotEmpty(purchaseapplyList)) {
            editDTO.setPurchaseapplyList(purchaseapplyList);
        }
        editDTO.setDictOption(getDictOption());
        return editDTO;
    }

    @Override
    public IPage<PurchaseapplyPageVO> getApplyPage(Page page, QueryWrapper<AssetPurchaseapply> query, AssetPurchaseapply entity) {
        query.eq("del_flag", 0);
        query.eq(StrUtil.isNotEmpty(entity.getStatus()), "status", entity.getStatus());
        IPage curPage = super.baseMapper.getApplyPage(page, query, new DataScope(), entity);
        Page resultPage = new Page(curPage.getCurrent(), curPage.getSize(), curPage.getTotal());
        List<AssetPurchaseapply> records = curPage.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            resultPage.setRecords(records.stream().map(r -> {
                PurchaseapplyPageVO purchaseapplyPageVO = new PurchaseapplyPageVO();
                BeanUtil.copyProperties(r, purchaseapplyPageVO);
                List<PurchaseapplyListPageVO> purchaseapplyList = this.purchaseapplyListService.listApplyPageVO(r);
                purchaseapplyPageVO.setPurchaseapplyList(purchaseapplyList);
                return purchaseapplyPageVO;
            }).collect(Collectors.toList()));
        }
        return resultPage;
    }

    @Override
    @PageSelectScope("GN_PURCHASE_APPLY")
    public IPage<AssetPurchaseapply> page(Page page, QueryWrapper<AssetPurchaseapply> query, PurchaseapplySearchDTO searchDTO, DataScope dataScope) {
        query.eq("del_flag", 0);
        return this.baseMapper.page(page, query, dataScope, searchDTO);
    }

    @Override
    public void updatePurchasedQuantity(List<AssetPurchaseorderList> purchaseOrderList, String batchnumber) {
        LambdaQueryWrapper<AssetPurchaseapplyList> lambdaQueryWrapper = Wrappers.<AssetPurchaseapplyList>query().lambda().eq(AssetPurchaseapplyList::getBatchnumber, batchnumber);
        List<AssetPurchaseapplyList> purchaseApplyList = this.purchaseapplyListService.list(lambdaQueryWrapper);
        if (CollUtil.isNotEmpty(purchaseApplyList) && CollUtil.isNotEmpty(purchaseOrderList)) {
            purchaseOrderList.forEach(purchaseOrder -> {
                purchaseApplyList.forEach(purchaseApply -> {
                    if (purchaseApply.getSauId().equals(purchaseOrder.getSauId())) {
                        purchaseApply.setPurchasedQuantity(purchaseOrder.getPurchasedQuantity());
                    }
                });
            });
            this.purchaseapplyListService.saveOrUpdateBatch(purchaseApplyList);
        }
    }

    @Override
    public void updateArrivedQuantity(List<AssetAcList> acList, String batchnumber) {
        LambdaQueryWrapper<AssetPurchaseapplyList> lambdaQueryWrapper = Wrappers.<AssetPurchaseapplyList>query().lambda().eq(AssetPurchaseapplyList::getBatchnumber, batchnumber);
        List<AssetPurchaseapplyList> purchaseApplyList = this.purchaseapplyListService.list(lambdaQueryWrapper);
        if (CollUtil.isNotEmpty(purchaseApplyList) && CollUtil.isNotEmpty(acList)) {
            acList.forEach(ac -> {
                purchaseApplyList.forEach(purchaseApply -> {
                    if (purchaseApply.getSauId().equals(ac.getSauId())) {
                        purchaseApply.setArrivedQuantity(ac.getArrivedQuantity());
                    }
                });
            });
            this.purchaseapplyListService.saveOrUpdateBatch(purchaseApplyList);
        }
    }

    @Override
    public String commit(AssetPurchaseapply purchaseapply) {
        String businessKey = purchaseapply.getUnid();
        //启动流程
        StartProcessInstanceVo startProcessInstanceVo = new StartProcessInstanceVo();
        startProcessInstanceVo.setBusinessKey(businessKey);
        CloudUser user = SecurityUtils.getUser();
        startProcessInstanceVo.setCurrentUserCode(user.getUsername());
        startProcessInstanceVo.setCreator(user.getUsername());
        startProcessInstanceVo.setFlowLevelFlag(true);
        startProcessInstanceVo.setAppSn("flow");

        startProcessInstanceVo.setFormName("采购申请" + purchaseapply.getCaseid());
        startProcessInstanceVo.setProcessDefinitionKey("PurchaseApply");
        Map<String, Object> variables = new HashMap<>();
        variables.put("approval", SecurityUtils.getUser().getUsername());
        startProcessInstanceVo.setVariables(variables);
        ReturnVo returnVo = new ReturnVo<>(ReturnCode.SUCCESS, "OK");
        ReturnVo<String> processInstanceReturnVo = remoteFlowableService.startProcessInstanceByKey(startProcessInstanceVo);

        if (processInstanceReturnVo.isSuccess()) {
            purchaseapply.setStatus("1");
            purchaseapply.setProcessInstanceId(processInstanceReturnVo.getData());
            returnVo.setData(purchaseapply);
        } else {
            returnVo.setCode(processInstanceReturnVo.getCode());
            returnVo.setMsg(processInstanceReturnVo.getMsg());
        }
        if (StrUtil.isNotEmpty(purchaseapply.getProcessInstanceId())) {
            this.updateById(purchaseapply);
        }
        return returnVo.getCode();
    }

    @Override
    public R batchDelete(List<Long> ids) {
        List<AssetPurchaseapply> purchaseapplyList = this.list(Wrappers.<AssetPurchaseapply>query().lambda().in(BaseEntity::getId, ids));
        if (CollUtil.isEmpty(purchaseapplyList)) {
            return R.failed("未找到相应的采购申请单数据");
        }
        CloudUser user = SecurityUtils.getUser();
        boolean allMatch = purchaseapplyList.stream().allMatch(purchaseapply -> AssetStatusEnum.DRAFT.getCode().equals(purchaseapply.getStatus()) && user.getId().equals(purchaseapply.getCreateId()));
        if (!allMatch) {
            return R.failed("只能删除草稿状态且创建用户为当前用户的采购申请单数据");
        }
        boolean remove = this.purchaseapplyListService.remove(Wrappers.<AssetPurchaseapplyList>query().lambda().in(AssetPurchaseapplyList::getParentId, ids));
        boolean delete = this.removeBatchByIds(ids);
        if (!delete && !remove) {
            return R.failed("删除失败，请检查数据有效性");
        }
        return R.ok(CommonConstants.SUCCESS, "删除成功");
    }

    private PurchaseapplyCreateDTO.DictOption getDictOption() {
        // 可选项和树
        PurchaseapplyCreateDTO.DictOption dictOption = new PurchaseapplyCreateDTO.DictOption();
        String[] dictOptionTypes = new String[]{AssetConstant.CURRENCY_TYPE, AssetConstant.TYPE_DOCUMENT, AssetConstant.PURCHASE_WAY};
        Map<String, List<DictItemOption>> resultMap = DictItemResolver.getDictOptionResultMap(dictOptionTypes);
        dictOption.setTypeList(resultMap.get(AssetConstant.TYPE_DOCUMENT));
        dictOption.setPurchaseWayList(resultMap.get(AssetConstant.PURCHASE_WAY));
        dictOption.setCurrencyTypeList(resultMap.get(AssetConstant.CURRENCY_TYPE));
        AssetSupplier fyAssetSupplier = new AssetSupplier();
        fyAssetSupplier.setType("V");
        dictOption.setSupplierTreeList(supplierService.selectTree(Wrappers.query(fyAssetSupplier)));
        dictOption.setDeptTreeList(deptService.tree().getData());
        dictOption.setBudgetTreeList(budgetService.selectBudgetTree());
        return dictOption;
    }

    private void beforeSave(AssetPurchaseapply entity) {
        // 补充金额和清单信息
        List<AssetPurchaseapplyList> purchaseapplyListList = entity.getPurchaseapplyList();
        if (CollUtil.isNotEmpty(purchaseapplyListList)) {
            StringBuilder detailed = new StringBuilder();
            purchaseapplyListList.forEach(p -> detailed.append(p.getName()).append(","));
            detailed.deleteCharAt(detailed.length() - 1);
            // 计算总金额
            BigDecimal amount = new BigDecimal(0);
            for (int i = 0; i < purchaseapplyListList.size(); i++) {
                AssetPurchaseapplyList purchaseapplyList = purchaseapplyListList.get(0);
                amount = amount.add(purchaseapplyList.getAmountSum());
            }
            entity.setAmount(amount);
            entity.setDetailed(detailed.toString());
        }
        String caseKey = ParamResolver.getStr("PURCHASEAPPLY_CASE_VALUE", "PR");
        if (StrUtil.isEmpty(entity.getBatchnumber())) {
            CloudUser user = SecurityUtils.getUser();
            String batchNumber = NumberResolver.getCodeByDateTime(caseKey, user.getId(), 5);
            entity.setBatchnumber(batchNumber);
        }
        if (StrUtil.isEmpty(entity.getCaseid())) {
            Map<String, String> numberMap = NumberResolver.getNumberMap(PurchaseConstant.PURCHASE_NUMBER_TYPE, DateUtil.format(new Date(), "yyyyMM"), 5L).getData();
            entity.setCaseid(caseKey + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN) + numberMap.get("code"));
        }
        // 采购单位
        if (entity.getPurchaseOuid() != null) {
            R<SysDept> r = remoteDeptService.getById(entity.getPurchaseOuid());
            if (r.getData() != null) {
                entity.setPurchaseOuname(r.getData().getName());
                entity.setPurchaseOufullname(r.getData().getFullName());
            }
        }
        // 预算
        if (entity.getBudgetId() != null) {
            AssetBudget budget = budgetMapper.selectById(entity.getBudgetId());
            if (budget != null) {
                entity.setBudgetName(budget.getNumber());
                entity.setBudgetNumber(budget.getNumber());
            }
        }
        // 供应商
        if (entity.getSupplierId() != null) {
            AssetSupplier fyAssetSupplier = supplierMapper.selectById(entity.getSupplierId());
            if (fyAssetSupplier != null) {
                entity.setSupplierName(fyAssetSupplier.getName());
            }
        }
    }
}
